using System;
using System.ComponentModel;

namespace InfiniTec
{
    public static class Enum<T>
    {
        public static T Parse(string value, bool ignoreCase)
        {
			if (string.IsNullOrEmpty(value)) return ConvertFrom(0);

            if (value.Contains(" ") && !value.Contains(","))
            {
                value = value.Replace(" ", ", ");
            }

            return (T) Enum.Parse(typeof (T), value, ignoreCase);
        }

        public static Type UnderlyingType { get { return Enum.GetUnderlyingType(typeof (T)); } }

        public static object ToUnderlyingType(T value)
        {
            TypeConverter converter = TypeDescriptor.GetConverter(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T));
            return converter.ConvertTo(value, UnderlyingType);
        }

        public static T Parse(string value)
        {
            if (string.IsNullOrEmpty(value)) throw new ArgumentNullException("value");

            if (value.Contains(" ") && !value.Contains(","))
            {
                value = value.Replace(" ", ", ");
            }

            return (T)Enum.Parse(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }

        public static T ConvertFrom(int value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }
        public static T ConvertFrom(short value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }
        public static T ConvertFrom(long value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }
		  [CLSCompliant(false)]
		  public static T ConvertFrom(sbyte value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }
        public static T ConvertFrom(byte value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }
        
        [CLSCompliant(false)]
        public static T ConvertFrom(ushort value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }
		  [CLSCompliant(false)]
		  public static T ConvertFrom(uint value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }
		  [CLSCompliant(false)]
		  public static T ConvertFrom(ulong value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }

        public static T ConvertFrom(object value)
        {
            return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value);
        }

        public static bool TryParse(string value, out T result)
        {
            if (string.IsNullOrEmpty(value)) throw new ArgumentNullException("value");

            try
            {
                if (value.Contains(" ") && !value.Contains(","))
                {
                    value = value.Replace(" ", ", ");
                }

                result = Parse(value);
                return true;
            }
            catch (ArgumentException)
            {
                result = default(T);
                return false;
            }
        }

        public static bool TryParse(string value, bool ignoreCase, out T result)
        {
            if (string.IsNullOrEmpty(value)) throw new ArgumentNullException("value");

            try
            {
                if (value.Contains(" ") && !value.Contains(","))
                {
                    value = value.Replace(" ", ", ");
                }

                result = Parse(value, ignoreCase);
                return true;
            }
            catch (ArgumentException)
            {
                result = default(T);
                return false;
            }
        }

        public static string Format(T value, string format)
        {
            return Enum.Format(typeof (T), value, format);
        }

        public static string ToString(T value, string delimiter)
        {
            string result = Format(value, "f");

            return result.Replace(", ", delimiter);
        }

    	public static bool IsDefined(T value)
    	{
    		return Enum.IsDefined(typeof (T), value);
    	}
    }
}
